package com.example.statistics.weight

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.os.SystemClock
import android.text.Editable
import android.text.InputFilter
import android.text.method.DigitsKeyListener
import android.text.method.TextKeyListener
import android.util.AttributeSet
import android.view.MotionEvent
import com.example.statistics.R
import com.example.statistics.ex.*
import kotlinx.coroutines.*
import org.jetbrains.anko.*
import java.util.*
import kotlin.math.cos


class TextProcessingView : androidx.appcompat.widget.AppCompatEditText {


    companion object {

        const val STYLE_DISPLAY = 0//显示
        const val STYLE_INPUT = 1//普通输入
        const val STYLE_INPUT_INT = 2//int数字✔
        const val STYLE_INPUT_FLOAT = 3//float数字✔
        const val STYLE_DATE = 4     //日期✔
        const val STYLE_REFRESH = 5  //刷新
        const val STYLE_REFRESH_INPUT = 6  //刷新
        const val STYLE_SEARCH = 7   //搜索
        const val STYLE_SELECTOR = 8 //选择
        const val STYLE_SELECTOR_JUMPS = 9 //选择
        const val STYLE_IMAGE = 9 //选择

        const val STYLE_MULTI_LEFT_RIGHT = 2
        const val STYLE_SWITCH = 3
        const val STYLE_TITLE = 5
        const val STYLE_MULTI_UP_DOWN = 6

    }


    private val spinSpeed = 200f
    private val barLength = 10
    private val barMaxLength = 300 //圆弧的最大值
    private var barExtraLength = 0f
    private val pauseGrowingDuration: Long = 150 //圆弧最长或最短状态在界面上显示的时间
    private val startGrowingDuration = 500.0 //圆弧由最长变最短或由最短变最长所有时间
    private val circlePaint = Paint()

    private var mProgress = 0.0f
    private var pauseGrowingTimer: Long = 0 //计时器
    private var startGrowingTimer = 0.0
    private var barGrowingFromFront = true
    private var lastTimeAnimated: Long = SystemClock.uptimeMillis()
    private var isRefresh = false


    private var defaultPaddingHorizontal = dip(20)
    private var isDefaultHeight: Boolean = true
    private var isDefaultTextSize = true
    private var isDefaultLine = true
    private var isDefaultPadding = true

    //label 基本信息
    var labelText: String? = null
    private val labelTextRect = Rect()
    private var isInitialize = true
    private val customPaint = Paint()


    var unitText: String? = null
    var datePattern = 0      //默认时间是yyyy-MM-dd
    var decimalDigits = 2    //小数位数
    private var drawableRes: Int? = null
    private val unitTextRect = Rect()
    private var integerDigits = 8    //整数位数
    private var drawableSize = dip(16)


    private var onContentClickedAction: ((String?) -> Unit)? = null
    private var onSymbolClickedAction: ((String?) -> Unit)? = null
    private var onRefreshClickedAction: (() -> Unit)? = null
    private var onDateClickedAction: ((String) -> Unit)? = null


    var contentText: String? = null
        get() = if (text?.toString() == "/" && style == ItemLayout.STYLE_DISPLAY) "" else text?.toString()
        set(value) {
            val text = if (value.isNumber()) {
                (value!!.toBigDecimal()).display()
            } else {
                value.orEmpty()
            }
            setText(text)
            field = value
        }


    //默认是显示样式
    var style = STYLE_DISPLAY
        set(value) {
            field = value
            initView()
        }


    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.TextProcessingView)
        isDefaultPadding = typedArray.getBoolean(R.styleable.TextProcessingView_tpv_is_default_padding, true)
        isDefaultLine = typedArray.getBoolean(R.styleable.TextProcessingView_tpv_is_default_line, true)
        isDefaultTextSize = typedArray.getBoolean(R.styleable.TextProcessingView_tpv_is_default_textSize, true)
        isDefaultHeight = typedArray.getBoolean(R.styleable.TextProcessingView_tpv_is_default_height, true)

        style = typedArray.getInt(R.styleable.TextProcessingView_tpv_style, STYLE_DISPLAY)
        //date
        datePattern = typedArray.getInt(R.styleable.TextProcessingView_tpv_date, 0)
        //number
        integerDigits = typedArray.getInt(R.styleable.TextProcessingView_tpv_integerDigits, integerDigits)
        decimalDigits = typedArray.getInt(R.styleable.TextProcessingView_tpv_decimalDigits, decimalDigits)

        labelText = typedArray.getString(R.styleable.TextProcessingView_tpv_label_text)
        unitText = typedArray.getString(R.styleable.TextProcessingView_tpv_unit_text)
        drawableSize = typedArray.getDimension(R.styleable.TextProcessingView_tpv_right_drawable_size, drawableSize.toFloat()).toInt()
        if (labelText != null) labelText = "$labelText："


        initView()
        typedArray.recycle()
    }

    private fun initView() {
        if (!isDefaultPadding) {
            defaultPaddingHorizontal = 0
        }
        setPadding(defaultPaddingHorizontal, 0, defaultPaddingHorizontal, 0)
        if (isDefaultTextSize) textSizeDimen = R.dimen.bill_text_label
        backgroundDrawable = if (isDefaultLine) context?.getResDrawable(R.drawable.bg_edittext_input) else null
        contentText = text.toString()
        if (isDefaultHeight) height = dip(48)

        //hint
        hint = if (style == STYLE_DISPLAY)
            ""
        else if (style == STYLE_REFRESH || STYLE_DATE == style || STYLE_SELECTOR == style || STYLE_SELECTOR_JUMPS == style)
            "请选择"
        else
            "请输入"

        //drawable
        drawableRes = when (style) {
            STYLE_DATE -> R.drawable.ic_date
            STYLE_SEARCH -> R.drawable.icon_search
            STYLE_SELECTOR, STYLE_SELECTOR_JUMPS -> R.drawable.ic_right_back
            else -> null
        }
    }


    override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter)
        if (style == STYLE_INPUT_FLOAT || style == STYLE_INPUT_INT || style == STYLE_REFRESH_INPUT) {
            numberInputLimit(editableText)
        }
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        paint.getTextBounds(labelText.orEmpty(), 0, labelText.orEmpty().length, labelTextRect)
        if (isInitialize) {
            leftPadding = paddingLeft + labelTextRect.right - labelTextRect.left + dip(5)
            rightPadding = if (style == STYLE_REFRESH || style == STYLE_REFRESH_INPUT || drawableRes != null) {
                defaultPaddingHorizontal * 2 + drawableSize
            } else {
                defaultPaddingHorizontal
            }
            isInitialize = false
        }
        if (isDefaultHeight) height = dip(48)

        if (!unitText.isNullOrBlank()) {
            paint.getTextBounds(unitText, 0, unitText.orEmpty().length, unitTextRect)
        }
    }

    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        customPaint.textSize = textSize
        customPaint.color = currentTextColor
        customPaint.isAntiAlias = true
        //文字基础线
        val fm = paint.fontMetrics
        val textBaseLine: Float = measuredHeight / 2 - (fm.bottom + fm.top) / 2
        //画标签label
        canvas?.drawText(labelText.orEmpty(), defaultPaddingHorizontal.toFloat(), textBaseLine, customPaint)

        //画右侧字,优先级：文字>刷新>其他图片
        if (!unitText.isNullOrEmpty()) {
            canvas?.drawText(
                unitText.orEmpty(),
                (width - unitTextRect.width() - defaultPaddingHorizontal).toFloat(),
                textBaseLine,
                customPaint
            )
        } else if (style == STYLE_REFRESH || style == STYLE_REFRESH_INPUT) {

            val startX = width - drawableSize - defaultPaddingHorizontal
            val startY = (height - drawableSize) / 2
            val endX = width - defaultPaddingHorizontal
            val endY = (height - drawableSize) / 2 + drawableSize
            val oval = RectF(startX.toFloat(), startY.toFloat(), endX.toFloat(), endY.toFloat())

            //画底层圆环
            circlePaint.isAntiAlias = true
            circlePaint.color = Color.LTGRAY
            circlePaint.style = Paint.Style.STROKE
            circlePaint.strokeWidth = dip(2).toFloat()
            canvas?.drawArc(oval, -90f, 360f, false, circlePaint)

            if (!isRefresh) {
                return
            }

            val deltaTime = SystemClock.uptimeMillis() - lastTimeAnimated
            val deltaNormalized = deltaTime * spinSpeed / 1000.0f
            updateBarLength(deltaTime)
            mProgress += deltaNormalized

            if (mProgress > 360) {
                mProgress -= 360f
            }

            var from = mProgress - 90
            var length = barLength + barExtraLength

            if (isInEditMode) {
                from = 0f
                length = 135f
            }
            circlePaint.color = Color.BLACK
            canvas?.drawArc(oval, from, length, false, circlePaint)
            lastTimeAnimated = SystemClock.uptimeMillis()
            postInvalidate()

        } else if (drawableRes != null) {
            drawableRes?.let {
                val bitmap = BitmapFactory.decodeResource(resources, it)
                val rect = Rect(
                    width - drawableSize - defaultPaddingHorizontal,
                    (height - drawableSize) / 2,
                    width - defaultPaddingHorizontal,
                    (height - drawableSize) / 2 + drawableSize
                )
                canvas?.drawBitmap(bitmap, null, rect, customPaint)
            }
        }
    }


    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event?.action == MotionEvent.ACTION_UP) {
            val contentRightPoint = if (!unitText.isNullOrBlank()) {
                right - (unitTextRect.width() + defaultPaddingHorizontal * 2)
            } else if (drawableRes != null || style == STYLE_REFRESH_INPUT || style == STYLE_REFRESH) {
                right - (drawableSize + defaultPaddingHorizontal * 2)
            } else {
                right - defaultPaddingHorizontal
            }

            val contentRect = Rect(
                (paint.measureText(labelText)).toInt() + defaultPaddingHorizontal,
                paddingTop,
                contentRightPoint,
                bottom - paddingBottom
            )

            val rightSymbolRect = Rect(
                width - (drawableSize + defaultPaddingHorizontal * 2),
                paddingTop,
                measuredWidth,
                bottom - paddingBottom
            )


            var rightTextRect: Rect? = null
            unitText?.let {
                rightTextRect = Rect(
                    right - (unitTextRect.width() + defaultPaddingHorizontal * 2),
                    paddingTop,
                    measuredWidth,
                    bottom - paddingBottom
                )
            }
            val isContentEvent = contentRect.contains(event.x.toInt(), event.y.toInt())
            val isSymbolEvent = rightSymbolRect.contains(event.x.toInt(), event.y.toInt())
            val isUnitEvent = rightTextRect?.contains(event.x.toInt(), event.y.toInt()) == true

            keyListener = null
            if (isContentEvent) {
                keyListener = if (style == STYLE_INPUT_INT)
                    DigitsKeyListener.getInstance("-0123456789")
                else if (style == STYLE_REFRESH_INPUT || STYLE_INPUT_FLOAT == style)
                    DigitsKeyListener.getInstance("-0123456789.")
                else if (style == STYLE_SEARCH || style == STYLE_REFRESH || style == STYLE_INPUT)
                    TextKeyListener.getInstance()
                else
                    null
            }

            if ((style == STYLE_REFRESH || style == STYLE_REFRESH_INPUT) && isSymbolEvent) { //刷新图标点击事件
                onRefreshClickedAction?.invoke()

            } else if (onSymbolClickedAction != null && (isSymbolEvent || isUnitEvent)) { //右侧图片或文字点击事件
                onSymbolClickedAction?.invoke(text.toString())

            } else if (onContentClickedAction != null && isContentEvent) { //内容点击事件
                onContentClickedAction?.invoke(text.toString())

            } else if (style == STYLE_DATE && (isContentEvent || isSymbolEvent)) { //日期点击事件
                val pattern = when (datePattern) {
                    1 -> "HH:mm"
                    2 -> "yyyy-MM-dd HH:mm"
                    3 -> "yyyy-MM"
                    else -> "yyyy-MM-dd"
                }
                val date = text.toString().parse()
                context.timePicker(date, pattern) {
                    val str = it.format(pattern)
                    setText(str)
                    onDateClickedAction?.invoke(str.orEmpty())
                }
            }
        }
        return super.onTouchEvent(event)
    }


    /**
     * 刷新事件
     */
    private fun updateBarLength(deltaTimeInMilliSeconds: Long) {
        if (pauseGrowingTimer >= pauseGrowingDuration) {
            startGrowingTimer += deltaTimeInMilliSeconds
            if (startGrowingTimer > startGrowingDuration) {
                startGrowingTimer -= startGrowingDuration
                pauseGrowingTimer = 0
                barGrowingFromFront = !barGrowingFromFront
            }

            val distance = cos((startGrowingTimer / startGrowingDuration + 1) * Math.PI).toFloat() / 2 + 0.5f
            val destLength = (barMaxLength - barLength).toFloat()

            if (barGrowingFromFront) {//圆弧边长
                barExtraLength = distance * destLength
            } else {
                val newLength = destLength * (1 - distance)
                mProgress += barExtraLength - newLength
                barExtraLength = newLength
            }
        } else {//圆弧处于最长或最短状态
            pauseGrowingTimer += deltaTimeInMilliSeconds
        }
    }

    private fun numberInputLimit(editable: Editable) {
        var str = editable.toString()
        if (str.contains(".")) { //设置输入最大长度
            if (integerDigits > 0) {
                filters = arrayOf<InputFilter>(InputFilter.LengthFilter(integerDigits + decimalDigits + 1))
            }
            //小数点只能出现1次
            var num = 0
            for (element in str) {
                if (element == '.') {
                    num++
                }
            }
            if (num > 1) {
                str = str.substring(0, str.length - 1)
                editable.replace(0, editable.length, str.trim { it <= ' ' })
            }
            //设置小数点位数
            if (str.length - (str.indexOf(".") + 1) > decimalDigits) {
                str = str.substring(0, str.length - 1)
                editable.replace(0, editable.length, str.trim { it <= ' ' })
            }
        } else {
            if (integerDigits > 0) {
                filters = arrayOf<InputFilter>(InputFilter.LengthFilter(integerDigits + 1))
                if (str.length > integerDigits) {
                    str = str.substring(0, integerDigits)
                    editable.replace(0, editable.length, str.trim { it <= ' ' })
                }
            }
        }
        //起始为.
        if (str.trim { it <= ' ' } == ".") {
            str = "0$str"
            editable.replace(0, editable.length, str.trim { it <= ' ' })
        }
        //起始为0
        if (str.startsWith("0") && str.trim { it <= ' ' }.length > 1) {
            if (str.substring(1, 2) != ".") {
                editable.replace(0, editable.length, "0")
            }
        }
    }

    fun isBlank(): Boolean {
        if (text.isNullOrBlank()) {
            val text = labelText.toString().replace("：", "").replace(" ", "")
            context.toast(hint.toString() + text)
            return true
        }
        return false
    }

    fun setRefreshStart() {
        this.isRefresh = true
        postInvalidate()
    }

    fun setRefreshStop(timeMillis: Long = 1000L) {
        GlobalScope.launch {
            delay(timeMillis)
            isRefresh = false
            postInvalidate()
        }
    }

    /**
     * 右侧刷新图标点击事件
     */
    fun onRefreshClicked(function: () -> Unit) {
        onRefreshClickedAction = function
    }

    /**
     * 日期点击事件
     */
    fun onDateClicked(function: (String) -> Unit) {
        onDateClickedAction = function
    }

    /**
     * 右侧内容点击事件
     */
    fun onContentClicked(function: (String?) -> Unit) {
        onContentClickedAction = function
    }

    /**
     * 右侧符号点击事件
     */
    fun onSymbolClicked(function: (String?) -> Unit) {
        onSymbolClickedAction = function
    }
}